# coding: utf-8

'''
Created on May 27, 2010

@author: guard
'''
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from ui import ui_game_plugins, ui_game_properties, ui_teams_properties, \
    ui_teams_same_city, ui_teams_same_group, ui_groups_properties, ui_screen_results
from plugins.plugin_base import PLUGIN_CATEGORIES, PLUGIN_TYPES, uid
from cgk.game import Team

PCG = PLUGIN_CATEGORIES.GAME
PTM = PLUGIN_TYPES.MAIN
PTA = PLUGIN_TYPES.ADDITIONAL

def table_client_width(tt):
    w = tt.size().width() - tt.verticalHeader().width()
    if tt.verticalScrollBar().isVisible():
        w -= tt.verticalScrollBar().width()
    return w    

class GamePluginsDialog(QDialog, ui_game_plugins.Ui_Dialog):
    def __init__(self, register_cls, active_plugins, parent=None):
        super(GamePluginsDialog, self).__init__(parent)
        self.setupUi(self)
        self.register_cls = register_cls
        self.active_plugins = active_plugins
        self.p_main = self.register_cls.plugins(PCG, PTM)[:]
        self.p_add = self.register_cls.plugins(PCG, PTA)[:]
        
        i = 0
        curr = None
        self.cbMain.addItem('', -1)
        for cls in self.p_main:
            s = u'[{0}] {1}'.format(cls.marker, cls.full_name)
            self.cbMain.addItem(s, i)
            i += 1
            if cls in self.active_plugins[uid(PCG, PTM)]:
                curr = i
        if curr is not None:
            self.cbMain.setCurrentIndex(curr)
        
        i = 0
        for cls in self.p_add:
            s = u'[{0}] {1}'.format(cls.marker, cls.full_name)
            li = QListWidgetItem(s)
            li.setCheckState(Qt.Checked if cls in self.active_plugins[uid(PCG, PTA)] else Qt.Unchecked)
            li.setData(Qt.UserRole, i)
            i += 1
            self.lAdditional.addItem(li)
                
    def accept(self):
        del self.active_plugins[uid(PCG, PTM)][:]
        i = self.cbMain.currentIndex()
        d = self.cbMain.itemData(i).toInt()[0]
        if d >= 0:
            self.active_plugins[uid(PCG, PTM)].append(self.p_main[d])
        del self.active_plugins[uid(PCG, PTA)][:]
        for i in range(self.lAdditional.count()):
            li = self.lAdditional.item(i)
            if li.checkState() == Qt.Checked:
                d = li.data(Qt.UserRole).toInt()[0]
                self.active_plugins[uid(PCG, PTA)].append(self.p_add[d])
        QDialog.accept(self)
        
class GamePropertiesDialog(QDialog, ui_game_properties.Ui_Dialog):
    def __init__(self, parent=None):
        super(GamePropertiesDialog, self).__init__(parent)
        self.setupUi(self)
 
class TeamsSetSameCityDialog(QDialog, ui_teams_same_city.Ui_Dialog):
    def __init__(self, parent=None):
        super(TeamsSetSameCityDialog, self).__init__(parent)
        self.setupUi(self)

class TeamsSetSameGroupDialog(QDialog, ui_teams_same_group.Ui_Dialog):
    def __init__(self, parent=None):
        super(TeamsSetSameGroupDialog, self).__init__(parent)
        self.setupUi(self)

class DynamicTableDialog(object):
    def __init__(self):
        self.__auto = False
        self._inputs = {}
        self.table.installEventFilter(self)
        
    def selected_rows(self):
        tt = self.table
        res = []
        for rr in tt.selectedRanges():
            res.extend(range(rr.topRow(), rr.bottomRow() + 1))
        res.sort()
        return res
        
    def _add_row(self, set_current=True, r=None, *args, **kwargs):
        self.__auto = True
        tt = self.table
        if r is None or r >= tt.rowCount():
            r = tt.rowCount()
            tt.setRowCount(r + 1)
        else:
            tt.insertRow(r)
        tt.setVerticalHeaderItem(r, QTableWidgetItem(unicode(r + 1)))
        if hasattr(self, '_fill_row'):
            self._fill_row(r, *args, **kwargs)
        for i in range(tt.columnCount()):
            w = tt.cellWidget(r, i)
            if w is not None:
                w.installEventFilter(self)
            self._inputs[w] = (r, i)
        if set_current:
            tt.setCurrentCell(r, 0)
        self.__auto = False
 
    def _move_row(self, to_row, from_row, *args, **kwargs):
        tt = self.table
        self._add_row(True, to_row)
        self.__auto = True
        if to_row < from_row:
            from_row += 1
        if hasattr(self, '_clone_row'):
            self._clone_row(to_row, from_row, *args, **kwargs)
        tt.removeRow(from_row)
        self.__auto = False
        
    def eventFilter(self, obj, event):
        if hasattr(self, 'table'):       
            tt = self.table
        else:
            tt = None
        if tt is None or self.__auto:
            return QWidget.eventFilter(self, obj, event)
        if event.type() == QEvent.KeyPress and event.key() in (Qt.Key_Tab, Qt.Key_Enter, Qt.Key_Return):
            r = tt.currentRow()
            c = tt.currentColumn()
            next_row = c == tt.columnCount() - 1 or event.key() in (Qt.Key_Enter, Qt.Key_Return)
            if next_row:
                if r == tt.rowCount() - 1:
                    self._add_row()
                else:
                    tt.setCurrentCell(r + 1, 0)
            else:
                tt.setCurrentCell(r, c + 1)
            return True
        elif event.type() == QEvent.FocusIn:
            if obj in self._inputs:
                tt.setCurrentCell(*self._inputs[obj])
            if tt.currentRow() == tt.rowCount() - 1:
                self._add_row(False)
            else:
                while tt.rowCount() > 2 and self.row_is_empty(tt.rowCount() - 2):
                    tt.removeRow(tt.rowCount() - 1)
        return QWidget.eventFilter(self, obj, event)
 
        
class TeamsPropertiesDialog(QDialog, ui_teams_properties.Ui_Dialog, DynamicTableDialog):
    def __init__(self, game, cities=[], parent=None):
        super(TeamsPropertiesDialog, self).__init__(parent)
        self.setupUi(self)

        self.cities = cities[:]
        self.cityCompleter = QCompleter(self.cities, self)        

        self.table = self.tableTeams
        DynamicTableDialog.__init__(self)
        
        self.__auto = False

        self.game = game
        
        if not self.game.groups:
            self.tableTeams.setColumnCount(3)
        
        if self.game.teams:
            tt = [(team.num - 1, team.id) for team in self.game.teams.values()]
            teams = {}
            for t in tt:
                teams[t[0]] = t[1]
            for j in range(max(teams.keys()) + 1):
                self._add_row(False, team=self.game.teams[teams[j]] if j in teams else None)
            
            if not self.game.groups:
                self.tableTeams.removeColumn(3)
                self.tableTeams.setColumnCount(3)
        
        self._add_row()
        self.tableTeams.setCurrentCell(0, 0)  
        self.tableTeams.clearSelection()
        
    def resizeEvent(self, size):
        tt = self.tableTeams
        w = table_client_width(tt)        
        w1 = w // 2
        w -= w1
        tt.setColumnWidth(0, w1 - 1)
        w2 = w // (tt.columnCount() - 1)
        tt.setColumnWidth(1, w2 - 1)
        w -= w2
        if tt.columnCount() > 3:
            w3 = w // 2
            tt.setColumnWidth(2, w3 - 1)
            w -= w3
            tt.setColumnWidth(3, w - 1)
        else:
            tt.setColumnWidth(2, w - 1)
        
    @pyqtSignature('')
    def on_bDelete_clicked(self):
        tt = self.tableTeams
        for r in reversed(self.selected_rows()):
            if r < tt.rowCount() - 1:
                tt.removeRow(r)
        tt.setVerticalHeaderLabels([str(x) for x in range(1, tt.rowCount() + 1)])
        tt.clearSelection()

    @pyqtSignature('')
    def on_bAdd_clicked(self):
        tt = self.tableTeams
        if not self.row_is_empty(tt.rowCount() - 1):
            self._add_row()
        else:
            tt.setCurrentCell(tt.rowCount() - 1, 0)    

    def _fill_row(self, r, team=None):
        tt = self.tableTeams
        if team:
            tt.verticalHeaderItem(r).setData(Qt.UserRole, team.id)
        else:
            tt.verticalHeaderItem(r).setData(Qt.UserRole, -1)
        tt.setCellWidget(r, 0, QLineEdit(team.name if team else ''))
        le = QLineEdit(team.city if team else '')
        le.setCompleter(self.cityCompleter)
        if self.cbSameCity.checkState() == Qt.Checked:
            le.setText(tt.cellWidget(0, 1).text())
            le.setEnabled(False)
        self.connect(le, SIGNAL('editingFinished()'), self.on_cityEdit_editingFinished)
        tt.setCellWidget(r, 1, le)
        tt.setCellWidget(r, 2, QLineEdit(team.captain if team else ''))
        if self.game.groups:
            cb = QComboBox()
            cb.addItem('', 0)
            i = 0
            curr = 0
            for n in sorted(self.game.groups.keys()):
                cb.addItem(self.game.groups[n], n)
                i += 1
                if team and team.id in self.game.teams_to_groups[n]:
                    curr = i
            tt.setCellWidget(r, 3, cb)
            cb.setCurrentIndex(curr)
    
    def _clone_row(self, to_row, from_row):
        tt = self.tableTeams
        tid = tt.verticalHeaderItem(from_row).data(Qt.UserRole).toInt()[0]
        for i in range(3):
            tt.cellWidget(to_row, i).setText(tt.cellWidget(from_row, i).text())
        if tt.columnCount() > 3:
            tt.cellWidget(to_row, 3).setCurrentIndex(tt.cellWidget(from_row, 3).currentIndex())
        tt.verticalHeaderItem(to_row).setData(Qt.UserRole, tid)


    @pyqtSignature('')
    def on_bUp_clicked(self):
        tt = self.tableTeams
        for r in self.selected_rows():
            if r > 0:
                self._move_row(r-1, r)
        tt.setVerticalHeaderLabels([str(x) for x in range(1, tt.rowCount() + 1)])
        tt.clearSelection()
        
    @pyqtSignature('')
    def on_bDown_clicked(self):
        tt = self.tableTeams
        for r in reversed(self.selected_rows()):
            if r < tt.rowCount() - 1:
                self._move_row(r+2, r)
        tt.setVerticalHeaderLabels([str(x) for x in range(1, tt.rowCount() + 1)])
        tt.clearSelection()

    @pyqtSignature('')
    def on_bSameCity_clicked(self):
        d = TeamsSetSameCityDialog(self)
        d.lineEdit.setCompleter(self.cityCompleter)
        if not d.exec_():
            return
        tt = self.tableTeams
        for rr in sorted(tt.selectedRanges(), key=lambda x: x.topRow()):
            for r in range(rr.topRow(), rr.bottomRow() + 1):
                tt.cellWidget(r, 1).setText(d.lineEdit.text())

    @pyqtSignature('')
    def on_bSameGroup_clicked(self):
        if not self.game.groups:
            return
        d = TeamsSetSameGroupDialog(self)
        d.comboBox.addItem('', 0)
        for n in sorted(self.game.groups.keys()):
            d.comboBox.addItem(self.game.groups[n], n)
        if not d.exec_():
            return
        tt = self.tableTeams
        for rr in sorted(tt.selectedRanges(), key=lambda x: x.topRow()):
            for r in range(rr.topRow(), rr.bottomRow() + 1):
                tt.cellWidget(r, 3).setCurrentIndex(d.comboBox.currentIndex())

    @pyqtSignature('int')
    def on_cbSameCity_stateChanged (self, state):
        if self.__auto:
            return
        tt = self.tableTeams
        if state == Qt.Checked:
            cities_ = [s for s in [self._city_in_row(r) for r in range(tt.rowCount())] if s]
            cities = []
            for c in cities_:
                if c not in cities:
                    cities.append(c)
            city = cities[0] if cities else ''
            if not cities and tt.rowCount() > 1:
                QMessageBox.information(self,
                                        u'Город не задан',
                                        u'На данный момент в таблице не указано ни одного города.'
                                        u' При сохранении будет использован город из первой строки. Ее можно оставить пустой.')
            elif len(cities) > 1:
                r = QMessageBox.warning(self,
                                        u'Задано более одного города',
                                        u'В таблие указано более одного города: {0}.'
                                        u' Если продолжить, использован будет город {1}. Продолжить?'.format(u', '.join(cities), city),
                                        QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel)
                if r == QMessageBox.No:
                    return
                elif r == QMessageBox.Cancel:
                    self.__auto = True
                    self.cbSameCity.setCheckState(Qt.Unchecked)
                    self.__auto = False
                    return
            self.bSameCity.setDisabled(True)
            for r in range(1, tt.rowCount()):                
                tt.cellWidget(r, 1).setText(city)
                tt.cellWidget(r, 1).setEnabled(False)                                    
        else:
            self.bSameCity.setDisabled(False)
            for r in range(tt.rowCount()):                
                tt.cellWidget(r, 1).setEnabled(True)                                    

    def row_is_empty(self, n):
        return not unicode(self.tableTeams.cellWidget(n, 0).text()).strip()
    
    def on_cityEdit_editingFinished(self):
        tt = self.tableTeams
        city = unicode(self.sender().text()).strip().title()
        if city:
            self.cities.append(city)
            self.cityCompleter.model().setStringList(self.cities)
        if self.cbSameCity.checkState() == Qt.Checked:
            for r in range(tt.rowCount()):                
                tt.cellWidget(r, 1).setText(city)

    def _city_in_row(self, r):
        tt = self.tableTeams
        return unicode(tt.cellWidget(r, 1).text()).strip().title()
    
    def accept(self):
        tt = self.tableTeams
        if self.game.teams:
            id = max(t for t in self.game.teams)
        else:
            id = -1
        teams = []
        if self.game.groups:
            t2g = {}
            for n in self.game.groups:
                t2g[n] = []
        for i in range(tt.rowCount()):
            if self.row_is_empty(i):
                continue
            tid = tt.verticalHeaderItem(i).data(Qt.UserRole).toInt()[0]
            if tid < 0:
                id += 1
                tid = id
            city = self._city_in_row(i)
            self.cities.append(city)
            teams.append(Team(tid, i + 1, unicode(tt.cellWidget(i, 0).text()).strip(), city,
                              unicode(tt.cellWidget(i, 2).text()).strip()))
            if self.game.groups:
                j = tt.cellWidget(i, 3).currentIndex()
                g = tt.cellWidget(i, 3).itemData(j).toInt()[0]
                if g > 0:
                    t2g[g].append(tid)
        self.game.update_teams(teams)
        if self.game.groups:
            self.game.teams_to_groups = t2g
        self.cities = list(set([s for s in self.cities if s]))
        self.cities.sort()
        QDialog.accept(self)

class GroupsPropertiesDialog(QDialog, ui_groups_properties.Ui_Dialog, DynamicTableDialog):        
    def __init__(self, game, parent=None):
        super(GroupsPropertiesDialog, self).__init__(parent)
        self.setupUi(self)

        self.__auto = False

        self.table = self.tableGroups
        DynamicTableDialog.__init__(self)
        
        self.game = game
        
        if self.game.groups:
            for j in sorted(self.game.groups.keys()):
                self._add_row(False, group=(j, self.game.groups[j]))
        
        self._add_row()
        tg = self.tableGroups
        tg.setCurrentCell(0, 0)  
        tg.clearSelection()     
        
    def resizeEvent(self, size):
        tg = self.tableGroups
        tg.setColumnWidth(0, table_client_width(tg))
        
    @pyqtSignature('')
    def on_bDelete_clicked(self):
        tg = self.tableGroups
        for r in reversed(self.selected_rows()):
            if r < tg.rowCount() - 1:
                tg.removeRow(r)
        tg.setVerticalHeaderLabels([str(x) for x in range(1, tg.rowCount() + 1)])
        tg.clearSelection()

    @pyqtSignature('')
    def on_bAdd_clicked(self):
        tg = self.tableGroups
        if not self.row_is_empty(tg.rowCount() - 1):
            self._add_row()
        else:
            tg.setCurrentCell(tg.rowCount() - 1, 0)    

    def _fill_row(self, r, group=None):
        tg = self.tableGroups
        if group:
            tg.verticalHeaderItem(r).setData(Qt.UserRole, group[0])
        else:
            tg.verticalHeaderItem(r).setData(Qt.UserRole, -1)
        tg.setCellWidget(r, 0, QLineEdit(group[1] if group else ''))
    
    def _clone_row(self, to_row, from_row):
        tg = self.tableGroups
        gid = tg.verticalHeaderItem(from_row).data(Qt.UserRole).toInt()[0]
        tg.cellWidget(to_row, 0).setText(tg.cellWidget(from_row, 0).text())
        tg.verticalHeaderItem(to_row).setData(Qt.UserRole, gid)

    @pyqtSignature('')
    def on_bUp_clicked(self):
        tg = self.tableGroups
        for r in self.selected_rows():
            if r > 0:
                self._move_row(r-1, r)
        tg.setVerticalHeaderLabels([str(x) for x in range(1, tg.rowCount() + 1)])
        tg.clearSelection()
        
    @pyqtSignature('')
    def on_bDown_clicked(self):
        tg = self.tableGroups
        for r in reversed(self.selected_rows()):
            if r < tg.rowCount() - 1:
                self._move_row(r + 2, r)
        tg.setVerticalHeaderLabels([str(x) for x in range(1, tg.rowCount() + 1)])
        tg.clearSelection()

    def row_is_empty(self, n):
        return not unicode(self.tableGroups.cellWidget(n, 0).text()).strip()
    
    def accept(self):
        tg = self.tableGroups
        groups = {}
        for i in range(tg.rowCount()):
            if self.row_is_empty(i):
                continue
            orig_id = tg.verticalHeaderItem(i).data(Qt.UserRole).toInt()[0]
            if orig_id < 0:
                orig_id = None
            group = unicode(tg.cellWidget(i, 0).text()).strip()
            groups[i + 1] = (group, orig_id)
        self.game.update_groups(groups)
        QDialog.accept(self)
        
class ScreenResultsDialog(QWidget, ui_screen_results.Ui_Dialog):
    def __init__(self, game, calc_results, calc_places, parent=None):
        super(ScreenResultsDialog, self).__init__(parent)
        self.setupUi(self)        
        self.installEventFilter(self)
        self.tableResults.installEventFilter(self)
        
        self.game = game
        self.prev_places = game.extraData('ResultsScreen/prev_places')[0]
        self.calc_results = calc_results
        self.calc_places = calc_places
        self.fill_table()
                        
        self.setWindowFlags(Qt.Dialog | Qt.WindowTitleHint)
        self.showMaximized()
        self._resize_table()
    
    def _resize_table(self):
        tr = self.tableResults
        w = table_client_width(tr)
        w2 = int (w / 2.5)
        w -= w2
        w1 = w // (tr.columnCount() - 1)
        w -= w1
        tr.setColumnWidth(0, w1 - 1)
        tr.setColumnWidth(1, w2 - 1)
        for i in range(tr.columnCount() - 2):
            w3 = w // (tr.columnCount() - 2 - i)
            tr.setColumnWidth(2 + i, w3 - 1)
            w -= w3
        
    def resizeEvent(self, size):
        self._resize_table()
        
    def fill_table(self):
        game = self.game
        results, plugins = self.calc_results()
        places = self.calc_places(results)
        deltas = {}
        if self.prev_places:
            for team_id in places:
                deltas[team_id] = self.prev_places[team_id] - places[team_id]
        self.prev_places = places
        game.setExtraData('ResultsScreen/prev_places', places, False)
        
        tr = self.tableResults
        tr.setColumnCount(2 + len(plugins))
        tr.setHorizontalHeaderLabels([u'М', u'Команда'] + [p.marker for p in plugins])
        tr.verticalHeader().hide()
        pp = {}
        for p in places.values():
            pp[p] = [] 
        for team_id in places:
            pp[places[team_id]].append(game.teams[team_id])
        for l in pp.values():
            l.sort(key=lambda x: x.num)
        
        i = 0
        curr_main = None
        curr_color = True
        c1 = QColor.fromRgba(0x9000CC00)
        c2 = QColor.fromRgba(0x9000CCCC)
         
        for p in pp:
            for team in pp[p]:
                tr.setRowCount(i + 1)
                place = str(p)
                if team.id in deltas and deltas[team.id]:
                    place += ' ({1}{0})'.format(deltas[team.id], '+' if deltas[team.id] > 0 else '')
                tr.setItem(i, 0, QTableWidgetItem(place))
                tr.setItem(i, 1, QTableWidgetItem(u'{0}. {1}'.format(team.num, team.name)))
                for j in range(len(plugins)):
                    tr.setItem(i, 2 + j, QTableWidgetItem(str(results[team.id][j])))
                if results[team.id][0] != curr_main:
                    curr_color = not curr_color
                    curr_main = results[team.id][0]
                for j in range(tr.columnCount()):
                    tr.item(i, j).setBackgroundColor(c1 if curr_color else c2)
                tr.setRowHeight(i, 45)             
                i += 1
    
    def toggle_fullscreen(self):
        if self.isFullScreen():
            #self.setWindowFlags(Qt.Dialog | Qt.WindowTitleHint)
            self.toolBar.show()
            if self._state == 'm':
                self.showMaximized()
            else:
                self.showNormal()
                self.setGeometry(self._geometry)
        else:
            self._state = 'm' if self.isMaximized() else 'n'
            self._geometry = self.geometry()
            self.toolBar.hide()
            #self.setWindowFlags(Qt.Tool | Qt.FramelessWindowHint)
            self.showFullScreen()
    
    @pyqtSignature('')
    def on_bFullScreen_clicked(self):
        self.toggle_fullscreen()
        
    def mouseDoubleClickEvent(self, event):
        self.toggle_fullscreen()

    def eventFilter(self, obj, event):
        if event.type() == QEvent.KeyPress:
            key = event.key() 
            if key == Qt.Key_F11:
                self.toggle_fullscreen()
                return True
            elif key == Qt.Key_F5:
                self.fill_table()
                return True
            elif key == Qt.Key_Escape:
                self.close()
        return QWidget.eventFilter(self, obj, event)
